'''
Created on 20/06/2014

@author: Vitor e Monique
'''
from funcoesEderivadas.embaralhadores import embaralhaListas

def redeNeural(entradas, zDesejados, omegasEntradaMeio, tetasMeio, omegasMeioSaida, tetaSaida, f, derF, passo = 0.1, tol = 0.1):
    numEntradas = len(entradas)
    it = 0
    erroTotal = 5
    listaErros = []
    
    while (erroTotal > tol and it < 10000):
        #print("\n---------------------------------------------------------------------------------------------------------------------")
        #print("\nIteração: "+str(it))
        
        erroTotal = 0
        
        #embaralha as listas
        entradas, zDesejados = embaralhaListas(entradas, zDesejados)
        
        #em todas as iterações, as letras tem os seguintes significados:
        #i sao os pares de padroes
        #j sao as entradas de cada par de padrao
        #k sao os neuronios da camada intermediaria
        #z sao os neuronios da camada de saida
        for i in range(numEntradas):
            #saidas da camada intermediaria
            kCalculado = []
            
            #print("\nEntrada " + str(i) + ":")
            
            #---------------------------------------------------------------------------------------------------------------------
            #calcula valor de saida dos neuronios da camada intermediaria
            for k in range(len(tetasMeio)):
                kCalcAtual = 0
                for j in range(len(entradas[i])):
                    kCalcAtual += entradas[i][j]*omegasEntradaMeio[j][k]
                kCalcAtual -= tetasMeio[k]
                
                kCalcAtual = f(kCalcAtual)
                
                kCalculado.append(kCalcAtual)
            
            #---------------------------------------------------------------------------------------------------------------------
            #calcula valor da saida da rede
            zCalculado = 0
            for k in range(len(tetasMeio)):
                zCalculado += kCalculado[k]*omegasMeioSaida[k]
            zCalculado -= tetaSaida
            
            zCalculado = f(zCalculado)
            
            #print("Saida Final: " + str(zCalculado))
            #print("Saida Desejada: " + str(zDesejados[i]))
            
            erroAtual = zCalculado - zDesejados[i]
            #print("Erro Atual: " + str(erroAtual))
            
            
            erroTotal += abs(erroAtual)
            
            #---------------------------------------------------------------------------------------------------------------------
            #calcula delta dos omegas da intermediaria para saida
            deltaOmegaMS = []
            for k in range(len(tetasMeio)):
                deltaOmegaMSatual = passo*erroAtual*derF(kCalculado[k])*kCalculado[k]
                deltaOmegaMS.append(deltaOmegaMSatual)
            
            #calcula matriz de deltas dos omegas da entrada para a intermediaria
            matrizDeltasEnMeio = [None]*len(entradas[i])
            for j in range(len(entradas[i])):
                matrizDeltasEnMeio[j] = []
                for k in range(len(tetasMeio)):
                    deltaOmegaEIatual = passo*entradas[i][j]*erroAtual*omegasMeioSaida[k]*derF(kCalculado[k])*derF(zCalculado)
                    matrizDeltasEnMeio[j].append(deltaOmegaEIatual)
            
            #---------------------------------------------------------------------------------------------------------------------
            #calcula os deltaTetas
            deltaTetaZ = passo*erroAtual*derF(zCalculado)
            
            deltaTetaK = []
            for k in range(len(tetasMeio)):
                deltaTetaKatual = passo*erroAtual*derF(zCalculado)*zCalculado
                deltaTetaK.append(deltaTetaKatual)
            
            #---------------------------------------------------------------------------------------------------------------------    
            #calcula novos omegas
            for k in range(len(tetasMeio)):
                omegasMeioSaida[k] -= deltaOmegaMS[k]
                
            for j in range(len(entradas[i])):
                for k in range(len(tetasMeio)):
                    omegasEntradaMeio[j][k] -= matrizDeltasEnMeio[j][k]
            
            #---------------------------------------------------------------------------------------------------------------------    
            #calcula novos tetas
            tetaSaida += deltaTetaZ
            
            for k in range(len(tetasMeio)):
                tetasMeio[k] -= deltaTetaK[k]
        
        #Fora For Maior
        #---------------------------------------------------------------------------------------------------------------------
        listaErros.append(erroTotal)
        #print("Erro Total: "+str(erroTotal))
        #print(erroTotal)
        it += 1
    
    #Fora While
    #---------------------------------------------------------------------------------------------------------------------
    return listaErros, omegasEntradaMeio, omegasMeioSaida, tetasMeio, tetaSaida